package com.flowplan.websocket.controller;

import com.flowplan.websocket.dto.CollaborationMessage;
import com.flowplan.websocket.dto.UserStatusMessage;
import com.flowplan.websocket.service.CollaborationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.annotation.SendToUser;
import org.springframework.stereotype.Controller;

import java.security.Principal;
import java.time.LocalDateTime;

/**
 * WebSocket协作控制器
 * 处理实时协作相关的WebSocket消息
 * 利用Java 21虚拟线程优化消息处理性能
 */
@Slf4j
@Controller
public class CollaborationWebSocketController {

    @Autowired
    private CollaborationService collaborationService;

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    /**
     * 处理用户加入协作会话
     */
    @MessageMapping("/collaboration/{projectId}/join")
    @SendTo("/topic/collaboration/{projectId}/users")
    public UserStatusMessage joinCollaboration(
            @DestinationVariable Long projectId,
            @Payload UserStatusMessage message,
            Principal principal) {
        
        // 使用虚拟线程处理用户加入逻辑
        Thread.startVirtualThread(() -> {
            try {
                String username = principal.getName();
                log.info("用户 {} 加入项目 {} 的协作会话", username, projectId);
                
                // 更新用户在线状态
                collaborationService.updateUserOnlineStatus(projectId, username, true);
                
                // 记录协作日志
                collaborationService.logCollaborationActivity(projectId, username, "JOIN", "用户加入协作");
                
            } catch (Exception e) {
                log.error("处理用户加入协作异常: {}", e.getMessage(), e);
            }
        });
        
        message.setUserId(principal.getName());
        message.setProjectId(projectId);
        message.setOnline(true);
        message.setTimestamp(LocalDateTime.now());
        
        return message;
    }

    /**
     * 处理用户离开协作会话
     */
    @MessageMapping("/collaboration/{projectId}/leave")
    @SendTo("/topic/collaboration/{projectId}/users")
    public UserStatusMessage leaveCollaboration(
            @DestinationVariable Long projectId,
            @Payload UserStatusMessage message,
            Principal principal) {
        
        // 使用虚拟线程处理用户离开逻辑
        Thread.startVirtualThread(() -> {
            try {
                String username = principal.getName();
                log.info("用户 {} 离开项目 {} 的协作会话", username, projectId);
                
                // 更新用户离线状态
                collaborationService.updateUserOnlineStatus(projectId, username, false);
                
                // 记录协作日志
                collaborationService.logCollaborationActivity(projectId, username, "LEAVE", "用户离开协作");
                
            } catch (Exception e) {
                log.error("处理用户离开协作异常: {}", e.getMessage(), e);
            }
        });
        
        message.setUserId(principal.getName());
        message.setProjectId(projectId);
        message.setOnline(false);
        message.setTimestamp(LocalDateTime.now());
        
        return message;
    }

    /**
     * 处理协作数据变更
     */
    @MessageMapping("/collaboration/{projectId}/data-change")
    @SendTo("/topic/collaboration/{projectId}/changes")
    public CollaborationMessage handleDataChange(
            @DestinationVariable Long projectId,
            @Payload CollaborationMessage message,
            Principal principal) {
        
        // 使用虚拟线程处理数据变更
        Thread.startVirtualThread(() -> {
            try {
                String username = principal.getName();
                log.info("用户 {} 在项目 {} 中进行数据变更: {}", username, projectId, message.getOperationType());
                
                // 冲突检测
                boolean hasConflict = collaborationService.detectConflict(projectId, message);
                if (hasConflict) {
                    // 发送冲突通知
                    CollaborationMessage conflictMessage = new CollaborationMessage();
                    conflictMessage.setMessageType("CONFLICT");
                    conflictMessage.setOperationType("CONFLICT_DETECTED");
                    conflictMessage.setUserId(username);
                    conflictMessage.setProjectId(projectId);
                    conflictMessage.setTimestamp(LocalDateTime.now());
                    conflictMessage.setData("检测到数据冲突，请刷新后重试");
                    
                    messagingTemplate.convertAndSend(
                        "/topic/collaboration/" + projectId + "/conflicts", 
                        conflictMessage
                    );
                    return;
                }
                
                // 应用数据变更
                collaborationService.applyDataChange(projectId, message);
                
                // 记录协作操作
                collaborationService.logCollaborationActivity(
                    projectId, username, message.getOperationType(), 
                    "数据变更: " + message.getData()
                );
                
            } catch (Exception e) {
                log.error("处理协作数据变更异常: {}", e.getMessage(), e);
                
                // 发送错误消息
                CollaborationMessage errorMessage = new CollaborationMessage();
                errorMessage.setMessageType("ERROR");
                errorMessage.setUserId(principal.getName());
                errorMessage.setProjectId(projectId);
                errorMessage.setTimestamp(LocalDateTime.now());
                errorMessage.setData("数据变更失败: " + e.getMessage());
                
                messagingTemplate.convertAndSendToUser(
                    principal.getName(), 
                    "/queue/errors", 
                    errorMessage
                );
            }
        });
        
        message.setUserId(principal.getName());
        message.setProjectId(projectId);
        message.setTimestamp(LocalDateTime.now());
        
        return message;
    }

    /**
     * 处理协作锁定请求
     */
    @MessageMapping("/collaboration/{projectId}/lock")
    @SendToUser("/queue/lock-response")
    public CollaborationMessage handleLockRequest(
            @DestinationVariable Long projectId,
            @Payload CollaborationMessage message,
            Principal principal) {
        
        CollaborationMessage response = new CollaborationMessage();
        response.setUserId(principal.getName());
        response.setProjectId(projectId);
        response.setTimestamp(LocalDateTime.now());
        
        // 使用虚拟线程处理锁定逻辑
        Thread.startVirtualThread(() -> {
            try {
                String username = principal.getName();
                String resourceId = message.getResourceId();
                
                boolean lockAcquired = collaborationService.acquireLock(projectId, resourceId, username);
                
                if (lockAcquired) {
                    response.setMessageType("LOCK_SUCCESS");
                    response.setData("资源锁定成功");
                    log.info("用户 {} 成功锁定项目 {} 的资源 {}", username, projectId, resourceId);
                    
                    // 通知其他用户资源被锁定
                    CollaborationMessage lockNotification = new CollaborationMessage();
                    lockNotification.setMessageType("RESOURCE_LOCKED");
                    lockNotification.setUserId(username);
                    lockNotification.setProjectId(projectId);
                    lockNotification.setResourceId(resourceId);
                    lockNotification.setTimestamp(LocalDateTime.now());
                    
                    messagingTemplate.convertAndSend(
                        "/topic/collaboration/" + projectId + "/locks", 
                        lockNotification
                    );
                } else {
                    response.setMessageType("LOCK_FAILED");
                    response.setData("资源已被其他用户锁定");
                    log.warn("用户 {} 锁定项目 {} 的资源 {} 失败", username, projectId, resourceId);
                }
                
                // 发送响应给请求用户
                messagingTemplate.convertAndSendToUser(
                    username, 
                    "/queue/lock-response", 
                    response
                );
                
            } catch (Exception e) {
                log.error("处理协作锁定请求异常: {}", e.getMessage(), e);
                response.setMessageType("LOCK_ERROR");
                response.setData("锁定请求处理失败: " + e.getMessage());
                
                messagingTemplate.convertAndSendToUser(
                    principal.getName(), 
                    "/queue/lock-response", 
                    response
                );
            }
        });
        
        return response;
    }

    /**
     * 处理协作解锁请求
     */
    @MessageMapping("/collaboration/{projectId}/unlock")
    @SendTo("/topic/collaboration/{projectId}/locks")
    public CollaborationMessage handleUnlockRequest(
            @DestinationVariable Long projectId,
            @Payload CollaborationMessage message,
            Principal principal) {
        
        // 使用虚拟线程处理解锁逻辑
        Thread.startVirtualThread(() -> {
            try {
                String username = principal.getName();
                String resourceId = message.getResourceId();
                
                boolean unlocked = collaborationService.releaseLock(projectId, resourceId, username);
                
                if (unlocked) {
                    log.info("用户 {} 成功解锁项目 {} 的资源 {}", username, projectId, resourceId);
                } else {
                    log.warn("用户 {} 解锁项目 {} 的资源 {} 失败", username, projectId, resourceId);
                }
                
            } catch (Exception e) {
                log.error("处理协作解锁请求异常: {}", e.getMessage(), e);
            }
        });
        
        message.setUserId(principal.getName());
        message.setProjectId(projectId);
        message.setMessageType("RESOURCE_UNLOCKED");
        message.setTimestamp(LocalDateTime.now());
        
        return message;
    }
}